package com.zidongxiangxi.lock.starter;

import com.zidongxiangxi.lock.core.DistributedLockFactory;
import com.zidongxiangxi.lock.redis.RedisDistributedLockFactory;
import com.zidongxiangxi.lock.starter.annotation.EnableDistributionLock;
import com.zidongxiangxi.lock.starter.aop.DistributedLockInterceptor;
import com.zidongxiangxi.lock.starter.aop.LockAnnotationAdvisor;
import com.zidongxiangxi.lock.starter.constant.DistributedLockConstants;
import com.zidongxiangxi.lock.zookeeper.ZookeeperDistributedLockFactory;
import org.apache.curator.framework.CuratorFramework;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

/**
 * 基于SpringBoot的自动配置实现
 *
 * @author chenxudong
 * @version 1.0.0
 */
@Configuration
@ConditionalOnBean(annotation = {EnableDistributionLock.class})
@EnableConfigurationProperties({DistributionLockConfigProperties.class})
public class DistributedLockAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(DistributedLockFactory.class)
    @ConditionalOnBean(RedissonClient.class)
    @ConditionalOnProperty(
        name = DistributedLockConstants.DISTRIBUTED_LOCK_TYPE_CONFIG,
        havingValue = DistributedLockConstants.REDIS_DISTRIBUTED_LOCK_TYPE,
        matchIfMissing = true)
    public DistributedLockFactory redisDistributedLockFactory(
        DistributionLockConfigProperties properties,
        RedissonClient redissonClient
    ) {
        return new RedisDistributedLockFactory(properties.getApplication(), redissonClient);
    }

    @Bean
    @ConditionalOnMissingBean(DistributedLockFactory.class)
    @ConditionalOnBean(CuratorFramework.class)
    @ConditionalOnProperty(
        name = DistributedLockConstants.DISTRIBUTED_LOCK_TYPE_CONFIG,
        havingValue = DistributedLockConstants.ZOOKEEPER_DISTRIBUTED_LOCK_TYPE)
    public DistributedLockFactory zookeeperDistributedLockFactory(
        DistributionLockConfigProperties properties,
        CuratorFramework curatorFramework
    ) {
        return new ZookeeperDistributedLockFactory(properties.getApplication(), curatorFramework);
    }

    @Bean
    public DistributedLockInterceptor lockInterceptor(DistributedLockFactory DistributedLockFactory) {
        return new DistributedLockInterceptor(DistributedLockFactory);
    }

    @Bean
    public LockAnnotationAdvisor lockAnnotationAdvisor(DistributedLockInterceptor lockInterceptor) {
        return new LockAnnotationAdvisor(lockInterceptor, Ordered.HIGHEST_PRECEDENCE);
    }
}
